package com.leonardo.beanme.model;

import java.util.Enumeration;
import java.util.Hashtable;

import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;

import MAR.Core.Reflector;

import com.leonardo.beanme.InputFieldChangeHandler;
import com.leonardo.beanme.exceptions.TypeInstantiationException;
import com.leonardo.beanme.fields.InputField;
import com.leonardo.beanme.metadatahandlers.FieldMetadataContainer;
import com.leonardo.beanme.metadatahandlers.FormMetadataContainer;
import com.leonardo.beanme.metadatahandlers.MetadataRepository;

public class BeanForm extends Form {
	
	private static final int initialCapacity = 10;
	private static Class type;
	
	private FormMetadataContainer conf;
	private Reflector reflector;
	private Hashtable fields = new Hashtable(initialCapacity);
	private FieldChangeListener fieldChangeListener;
		
	public BeanForm(Object obj) throws Exception{
		this(obj, null);
	}
	
	public BeanForm(Object obj, String beanId) throws Exception {
		super("Form");
		type = obj.getClass();
		this.fieldChangeListener = new FieldChangeListener();
		this.setItemStateListener(this.fieldChangeListener);
		this.conf = MetadataRepository.getInstance().getConfiguration(obj.getClass(), beanId);
		this.reflector = (Reflector) obj;
		this.addFields();
		populate();
	}
	
	public BeanForm(Class type) throws Exception {
		this(type, null);
	}
	
	public BeanForm(Class type, String beanId) throws TypeInstantiationException, ClassNotFoundException {
		super("Form");
		BeanForm.type = type;
		this.fieldChangeListener = new FieldChangeListener();
		this.setItemStateListener(this.fieldChangeListener);
		this.conf = MetadataRepository.getInstance().getConfiguration(type, beanId);
		try {
			this.reflector = (Reflector) type.newInstance();
		} catch (IllegalAccessException ex) {
			throw new TypeInstantiationException(type);
		} catch(InstantiationException ex) {
			throw new TypeInstantiationException(type);
		}
		addFields();
	}
	
	private void addFields() throws TypeInstantiationException, ClassNotFoundException {
		conf.reset();
		while(conf.hasMoreFields()) {
			FieldMetadataContainer field = conf.next();
			field.addItselfIn(this);
		}
	}
	
	private void populate() throws Exception  {
		conf.reset();
		while(conf.hasMoreFields()) {
			FieldMetadataContainer field = conf.next();
			Object getResult = reflector.invokeMethod(field.getGetter(), null);
			((InputField) fields.get(field)).setValue(getResult);
		}
	}
			
	public Object getBean() throws Exception  {
		conf.reset();
		while(conf.hasMoreFields()) {
			FieldMetadataContainer field = conf.next();
			InputField inputField = (InputField) fields.get(field);
			reflector.invokeMethod(field.getSetter(), new Object[] {inputField.getValue()});
		}
		return reflector;
	}
	
	public void putField(FieldMetadataContainer field, InputField input) {
		fields.put(field, input);
	}
	
	public void addListener(InputFieldChangeHandler handler) {
		fieldChangeListener.addListener(handler);
	}
	
	public void clear() {
		Enumeration it = fields.keys();
		while(it.hasMoreElements()) {
			((InputField) fields.get(it.nextElement())).clear();
		}
	}
	
	protected Object getObj() {
		return reflector;
	}

	protected void setObj(Object obj) {
		reflector = (Reflector) obj;
	}

	protected static void setType(Class type) {
		BeanForm.type = type;
	}

	public static Class getType() {
		return type;
	}
	
	public class FieldChangeListener implements ItemStateListener {

		private Hashtable handlers = new Hashtable();  
		
		public void itemStateChanged(Item item) {
			if(handlers.containsKey(item))
				((InputFieldChangeHandler) handlers.get(item)).onChange();
		}
		
		public void addListener(InputFieldChangeHandler handler) {
			handlers.put(handler.getField().getField(), handler);
		}
		
	}
	
}
